﻿using Microsoft.Practices.Prism.Logging;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.Practices.ServiceLocation;
using System.Linq;
using System;

namespace OpenLightGroup.Prism
{


    [PartCreationPolicy(CreationPolicy.Shared)]
    [Export("ICompositeLogger", typeof(ICompositeLogger))]
    [Export("ILoggerFacade", typeof(ILoggerFacade))]
    [Export("CompositeLogger", typeof(CompositeLogger))]
    public class CompositeLogger
        : ICompositeLogger
    {

        private readonly Dictionary<string, ILoggerFacade> _registrations
            = new Dictionary<string, ILoggerFacade>();

        #region ICompositeLogger Members


        /// <summary>
        /// Gets the <see cref="Microsoft.Practices.Prism.Logging.ILoggerFacade"/> with the specified key.
        /// </summary>
        public virtual ILoggerFacade this[string key]
        {
            get
            {
                return _registrations[key] ;
            }
        }

        /// <summary>
        /// Gets a dictionary of the registered loggers and their keys.
        /// </summary>
        /// <value>The loggers.</value>
        public virtual IEnumerable<KeyValuePair<string, ILoggerFacade>> Loggers
        {
            get
            {
                return _registrations ;
            }
        }

        /// <summary>
        /// Gets the logger of a specified type. If there are more than one loggers of the specified type it will return the first one.
        /// </summary>
        /// <typeparam name="T">The concrete type of a ILoggerFacade</typeparam>
        /// <returns></returns>
        public virtual T GetLogger<T>() where T : ILoggerFacade
        {
            return GetLogger<T>(String.Empty);
        }

        /// <summary>
        /// Gets the logger of a specified type that is registered with the specified key.
        /// </summary>
        /// <typeparam name="T">The concrete type of a ILoggerFacade</typeparam>
        /// <param name="key">The key that the logger was registered with.</param>
        /// <returns></returns>        
        public virtual T GetLogger<T>(string key) where T : ILoggerFacade
        {

            var loggers = from l in _registrations
                         where l.Value.GetType() == typeof(T)
                         select l;

            if(!String.IsNullOrEmpty(key))
                loggers = loggers.Where( l => l.Key == key ) ;


            if (loggers != null && loggers.Count() > 0)
                return (T)loggers.FirstOrDefault().Value;
            else
                throw new KeyNotFoundException();
        }

        /// <summary>
        /// Registers the instance of the logger using the key provided.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="logger">The logger instance.</param>
        public virtual void RegisterLogger (string key, ILoggerFacade logger)
        {
            _registrations.Add( key, logger ) ;
        }

        /// <summary>
        /// Will retrieve the instance of the logger from the ServiceLocator based on key 
        /// and add it to the list of loggers.
        /// </summary>
        /// <param name="key"></param>
        public virtual void RegisterLogger(string key)
        {
            try
            {
                if (ServiceLocator.Current != null)
                {
                    ILoggerFacade logger = null;

                    logger = ServiceLocator.Current.GetInstance<ILoggerFacade>(key);

                    this.RegisterLogger(key, logger);
                }
            }
            catch (System.Exception ex)
            {
                this.Log(String.Format("Could not register logger (Key: {0})", key), Category.Exception, Priority.Medium);
                this.Log(ex.Message, Category.Exception, Priority.Medium);
            }

        }

        /// <summary>
        /// Unregisters the logger and removes it from the Loggers list.
        /// </summary>
        /// <param name="key">The key of the logger to remove..</param>
        public virtual void UnregisterLogger ( string key )
        {
            if ( _registrations.ContainsKey( key ) )
            {
                _registrations.Remove(key);
            }
        }

        #endregion

        #region ILoggerFacade Members

        /// <summary>
        /// Logs the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="category">The category.</param>
        /// <param name="priority">The priority.</param>
        public virtual void Log ( string message, Category category, Priority priority )
        {

            lock (_registrations)
            {
                KeyValuePair<System.String, ILoggerFacade>[] _temp = _registrations.ToArray();

                foreach (var item in _temp)
                {
                    if (item.Value == null)
                    {
                        try
                        {
                            _registrations[item.Key] = ServiceLocator.Current.GetInstance<ILoggerFacade>(item.Key);
                        }
                        catch (System.Exception)
                        {

                        }
                    }

                    if (item.Value != null)
                        item.Value.Log(message, category, priority);
                }
            }
        }

        #endregion

    }
  

}